package puntaelena.facilitylocation.hillclimbing.solver;

import static puntaelena.facilitylocation.hillclimbing.solver.agents.FcltCityNegotiateComputator.*;
import puntaelena.facilitylocation.hillclimbing.solver.services.NOPFcltCoalitionEventsListener;
import puntaelena.facilitylocation.hillclimbing.solver.services.IServicesFcltLocSolver;
import puntaelena.graphsupport.solver.IFacilityLocationSolver;
import puntaelena.graphsupport.FacilitiesGraph;
import jfuzzyprincepless.algorithm.structure.INegotiationConstruction;
import jfuzzyprincepless.negotiation.DefaultNegotiation;
import jfuzzyprincepless.negotiation.INegotiation;
import jfuzzyprincepless.negotiation.INegotiationContext;
import jfuzzyprincepless.negotiation.services.IService;

public class HillClimbingSolver
	implements IFacilityLocationSolver, IServicesFcltLocSolver
{
	private IFacilityLocationSolver subSolver;
	private INegotiation negotiation = new DefaultNegotiation();
	private INegotiationConstruction algorithm = null;

	public HillClimbingSolver(
		IFacilityLocationSolver subSolver,
		INegotiationConstruction algorithm
	) {
		this.subSolver = subSolver;
		this.algorithm = algorithm;
	}

	@Override
	public void solve(
		FacilitiesGraph fgraph,
		boolean[] isFcltOpen,
		int[] witnesses
	) {
		solve(
			fgraph,
			isFcltOpen,
			witnesses,
			new NOPFcltCoalitionEventsListener()
		);
	}

	public void solve(
		FacilitiesGraph fgraph,
		boolean[] isFcltOpen,
		int[] witnesses,
		IService ... extraServices
	) {
		subSolver.solve(fgraph, isFcltOpen, witnesses);

		INegotiationContext context =
			createHillClimbingNegotiationContext();
		initHillClimbingServices(
				context,
				fgraph,
				isFcltOpen,
				witnesses
			);
		context.registerService(algorithm);
		for (IService service : extraServices) {
			context.registerService(service);
		}

		negotiation.negotiate(context);
	}
}
